/*
 * Copyright (c) 2023-2025 elsfs Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.elsfs.cloud.common.mybatis.ext.sql;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import org.elsfs.cloud.common.core.entity.BaseEntity;
import org.elsfs.cloud.common.mybatis.ext.sql.support.common.FieldEnumResolverSupport;
import org.elsfs.cloud.common.mybatis.ext.sql.support.update.CompositeSetItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.update.ExpressionSetItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.update.SetItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.update.StandardSetItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.update.StandardUpdateItem;
import org.elsfs.cloud.common.mybatis.ext.sql.support.update.UpdateItem;

/**
 * 抽象更新SQL实现
 *
 * @param <C> 子类具体类型
 */
@SuppressWarnings("unchecked")
public abstract class AbstractUpdateSql<C extends AbstractUpdateSql<C>> extends AbstractJoin<C>
    implements UpdateSql<C, AbstractUpdateSql<C>.UpdateConditionBuilderImpl> {

  /** 具体子类实现引用 */
  protected final C childThis = (C) this;

  /** 更新表 */
  private UpdateItem updateItem;

  /** 更新设置项 */
  private final Collection<SetItem> setItems = new ArrayList<>();

  /** 更新条件构建器 */
  private UpdateConditionBuilderImpl updateConditionBuilder;

  /**
   * 设置更新数据的表
   *
   * @param entityClass 实体类
   * @return 具体实现
   */
  @Override
  public C update(Class<? extends BaseEntity> entityClass) {
    this.updateItem =
        new StandardUpdateItem(TableInfoHelper.getTableInfo(entityClass).getTableName(), null);

    return this.childThis;
  }

  /**
   * 设置更新数据的表
   *
   * @param table 表名
   * @return 具体实现
   */
  @Override
  public C update(String table) {
    this.updateItem = new StandardUpdateItem(table, null);

    return this.childThis;
  }

  /**
   * 设置更新数据的表
   *
   * @param entityClass 实体类
   * @param tableAlias 表别名
   * @return 具体实现
   */
  @Override
  public C update(Class<? extends BaseEntity> entityClass, String tableAlias) {
    this.updateItem =
        new StandardUpdateItem(
            TableInfoHelper.getTableInfo(entityClass).getTableName(), tableAlias);

    return this.childThis;
  }

  /**
   * 设置更新数据的表
   *
   * @param table 表名
   * @param tableAlias 表别名
   * @return 具体实现
   */
  @Override
  public C update(String table, String tableAlias) {
    this.updateItem = new StandardUpdateItem(table, tableAlias);

    return this.childThis;
  }

  /**
   * 设置字段表达式
   *
   * @param field 字段名称
   * @param expression 表达式
   * @param args 表达式参数
   * @return 具体实现
   */
  @Override
  public C set(String field, String expression, Object... args) {
    this.setItems.add(new ExpressionSetItem(field, expression, args));

    return this.childThis;
  }

  /**
   * 设置字段表达式
   *
   * @param field 字段枚举
   * @param expression 表达式
   * @param args 表达式参数
   * @return 具体实现
   */
  @Override
  public C set(Enum<?> field, String expression, Object... args) {
    return this.set(
        FieldEnumResolverSupport.resolveFieldName(this.getTableAliasManager(), field),
        expression,
        args);
  }

  /**
   * 设置字段值
   *
   * @param field 字段名称
   * @param value 值
   * @return 具体实现
   */
  @Override
  public C setValue(String field, Object value) {
    this.setItems.add(new StandardSetItem(this.getSqlParameterManager(), field, value));

    return this.childThis;
  }

  /**
   * 设置字段值
   *
   * @param field 字段枚举
   * @param value 值
   * @return 具体实现
   */
  @Override
  public C setValue(Enum<?> field, Object value) {
    return this.setValue(
        FieldEnumResolverSupport.resolveFieldName(this.getTableAliasManager(), field), value);
  }

  /**
   * 批量设置字段值
   *
   * @param fieldValueMap 字段值Map
   * @return 具体实现
   */
  @Override
  public C setValues(Map<String, Object> fieldValueMap) {
    for (Map.Entry<String, Object> entry : fieldValueMap.entrySet()) {
      this.setValue(entry.getKey(), entry.getValue());
    }

    return this.childThis;
  }

  /**
   * 批量设置字段值
   *
   * @param fieldValueMap 字段枚举值Map
   * @return 具体实现
   */
  @Override
  public C setValuesEnum(Map<Enum<?>, Object> fieldValueMap) {
    for (Map.Entry<Enum<?>, Object> entry : fieldValueMap.entrySet()) {
      this.setValue(entry.getKey(), entry.getValue());
    }

    return this.childThis;
  }

  /**
   * 设置更新条件
   *
   * @return 更新条件构建器
   */
  @Override
  public UpdateConditionBuilder<UpdateConditionBuilderImpl, C> where() {
    if (this.updateConditionBuilder == null) {
      this.updateConditionBuilder = new UpdateConditionBuilderImpl();
    }

    return this.updateConditionBuilder;
  }

  /** 构建SQL之前处理 */
  @Override
  protected void beforeBuild() {
    this.addSqlFragment(new TokenSqlFragment("UPDATE"));
    if (this.updateItem == null) {
      throw new MybatisPlusException("更新SQL的表必须指定");
    }
    this.addSqlFragment(this.updateItem);
    if (this.setItems.isEmpty()) {
      throw new MybatisPlusException("更新SQL必须设置更新项");
    }
    super.beforeBuild();
    this.addSqlFragment(new CompositeSetItem(this.setItems));
    if (this.updateConditionBuilder != null) {
      this.addSqlFragment(this.updateConditionBuilder);
    }
  }

  /** 更新条件构建器实现 */
  public class UpdateConditionBuilderImpl
      extends AbstractSortableConditionBuilder<UpdateConditionBuilderImpl>
      implements UpdateConditionBuilder<UpdateConditionBuilderImpl, C> {

    /**
     * 返回上一级对象
     *
     * @return 上级对象
     */
    @Override
    public C end() {
      return AbstractUpdateSql.this.childThis;
    }

    /**
     * 获取SQL参数管理器
     *
     * @return SQL参数管理器
     */
    @Override
    public SqlParameterManager getSqlParameterManager() {
      return AbstractUpdateSql.this.getSqlParameterManager();
    }

    /**
     * 获取表别名管理器
     *
     * @return 表名别管理器
     */
    @Override
    public TableAliasManager getTableAliasManager() {
      return AbstractUpdateSql.this.getTableAliasManager();
    }
  }
}
